

package cn.edu.nsmc.modules.sys.service.impl;

import cn.edu.nsmc.common.utils.R;
import cn.edu.nsmc.config.Constant;
import cn.edu.nsmc.modules.sys.entity.excel.SysUserEntityExcel;
import cn.edu.nsmc.modules.sys.entity.vo.SysUserVO;
import cn.edu.nsmc.utils.FileUtils;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.edu.nsmc.common.exception.RRException;
import cn.edu.nsmc.common.utils.PageUtils;
import cn.edu.nsmc.common.utils.Query;
import cn.edu.nsmc.modules.sys.dao.SysUserDao;
import cn.edu.nsmc.modules.sys.entity.SysUserEntity;
import cn.edu.nsmc.modules.sys.service.SysRoleService;
import cn.edu.nsmc.modules.sys.service.SysUserRoleService;
import cn.edu.nsmc.modules.sys.service.SysUserService;
import com.mchange.lang.IntegerUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * 系统用户
 *
 *
 */
@Service("sysUserService")
@Slf4j
public class SysUserServiceImpl extends ServiceImpl<SysUserDao, SysUserEntity> implements SysUserService {
	@Autowired
	private SysUserRoleService sysUserRoleService;
	@Autowired
	private SysRoleService sysRoleService;
	@Autowired
	private FileUtils fileUtils;
	@Autowired
	private SysUserDao sysUserDao;

	@Override
	public PageUtils queryPage(Map<String, Object> params) {
		String username = (String)params.get("username");
		Long createUserId = (Long)params.get("createUserId");

		IPage<SysUserEntity> page = this.page(
				new Query<SysUserEntity>().getPage(params),
				new QueryWrapper<SysUserEntity>()
						.like(StringUtils.isNotBlank(username),"username", username)
						.eq(createUserId != null,"create_user_id", createUserId)
						.eq("type", 1).orderByDesc("user_id")
		);

		return new PageUtils(page);
	}

	@Override
	public PageUtils queryPageSysUserVO(Map<String, Object> params) {
		String username = (String)params.get("username");
		int userType = IntegerUtils.parseInt((String)params.get("userType"), -1);

		IPage<SysUserEntity> page = this.page(
				new Query<SysUserEntity>().getPage(params),
				new QueryWrapper<SysUserEntity>()
						.like(StringUtils.isNotBlank(username),"username", username)
						.eq(userType != -1,"type", userType)
		);

		// Convert SysUserEntity list to SysUserVO list
		List<SysUserVO> voList = page.getRecords().stream().map(entity -> {
			SysUserVO vo = new SysUserVO();
			BeanUtils.copyProperties(entity, vo);
			return vo;
		}).collect(Collectors.toList());

		// Create a new Page object for SysUserVO
		IPage<SysUserVO> voPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
		voPage.setRecords(voList);

		return new PageUtils(voPage);
	}

	@Override
	public List<String> queryAllPerms(Long userId) {
		return baseMapper.queryAllPerms(userId);
	}

	@Override
	public List<Long> queryAllMenuId(Long userId) {
		return baseMapper.queryAllMenuId(userId);
	}

	@Override
	public SysUserEntity queryByUserName(String username) {
		return baseMapper.queryByUserName(username);
	}

//	public static void main(String[] args) {
//		String salt = RandomStringUtils.randomAlphanumeric(20);
//		System.out.println(salt);
//		System.out.println(new Sha256Hash("admin", salt).toHex());
//	}

	@Override
	@Transactional
	public void saveUser(SysUserEntity user) {
		user.setCreateTime(new Date());
		//sha256加密
		String salt = RandomStringUtils.randomAlphanumeric(20);
		user.setPassword(new Sha256Hash(user.getPassword(), salt).toHex());
		user.setSalt(salt);
		this.save(user);

		//检查角色是否越权
		checkRole(user);

		//保存用户与角色关系
		sysUserRoleService.saveOrUpdate(user.getUserId(), user.getRoleIdList());
	}

	@Override
	@Transactional
	public void update(SysUserEntity user) {
		if(StringUtils.isBlank(user.getPassword())){
			user.setPassword(null);
		}else{
			user.setPassword(new Sha256Hash(user.getPassword(), user.getSalt()).toHex());
		}
		this.updateById(user);

		//检查角色是否越权
		checkRole(user);

		//保存用户与角色关系
		sysUserRoleService.saveOrUpdate(user.getUserId(), user.getRoleIdList());
	}

	@Override
	public void deleteBatch(Long[] userId) {
		this.removeByIds(Arrays.asList(userId));
	}

	@Override
	public boolean updatePassword(Long userId, String password, String newPassword) {
		SysUserEntity userEntity = new SysUserEntity();
		userEntity.setPassword(newPassword);
		return this.update(userEntity,
				new QueryWrapper<SysUserEntity>().eq("user_id", userId).eq("password", password));
	}

	@Override
	public SysUserEntity queryByMobile(String mobile) {
		return getOne(new LambdaQueryWrapper<SysUserEntity>().eq(SysUserEntity::getMobile,mobile));
	}

	@Override
	public SysUserEntity wxUpdate(SysUserEntity user) {
		this.updateById(user);

		SysUserEntity byId = getById(user);
		byId.setPassword(null).setSalt(null);
		return byId;
	}

	@Override
	public void getExcelTemplate(HttpServletResponse response) {
		try {
			fileUtils.getExcelFile("userExcel.xlsx",response);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@Override
	public R importUser(MultipartFile file, Long userId) {
		if (userId==null){
			return R.error("获取用户ID失败");
		}
		InputStream in = null;
		try {
			in = file.getInputStream();
		} catch (IOException e) {
			R.error("读取文件失败");
		}
		Date creationTime=new Date(System.currentTimeMillis());
		EasyExcel.read(in, SysUserEntityExcel.class, new ReadListener<SysUserEntityExcel>() {
			/**
			 * 单次缓存的数据量
			 */
			public static final int BATCH_COUNT = 30;
			/**
			 *临时存储
			 */
			private List<SysUserEntityExcel> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

			@Override
			public void invoke(SysUserEntityExcel data, AnalysisContext context) {
				data.setSalt(RandomStringUtils.randomAlphanumeric(20));
				data.setPassword(new Sha256Hash(Constant.DEFAULT_PASSWORD, data.getSalt()).toHex());
				//data.setStatus(1);
				//data.setType(5);
				data.setTypeInt(Constant.TYPE_TO_INT.get(data.getType()));
				if ("男".equals(data.getGenderString())){
					data.setGender(1);
				}else {
					data.setGender(0);
				}
				//默认的角色Id
				//获取创建者Id并设置
				data.setCreateTime(creationTime);
				//data.setMiniUse(0);
				//data.setMiniAttention(0);
				//询问小程序的逻辑
				cachedDataList.add(data);
				if (cachedDataList.size() >= BATCH_COUNT) {
					saveData();
					// 存储完成清理 list
					cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
				}
			}

			@Override
			public void doAfterAllAnalysed(AnalysisContext context) {
				saveData();
			}

			/**
			 * 加上存储数据库
			 */
			private void saveData() {
				log.info("{}条数据，开始存储数据库！", cachedDataList.size());
				//to save
//                System.out.println(cachedDataList);
				sysUserDao.importRepairman(userId,cachedDataList);
				log.info("存储数据库成功！");
			}
		}).sheet().doRead();
		return R.ok("导入用户信息成功");
	}

	@Override
	public void exportUser(SysUserEntity sysUserEntity, HttpServletResponse response) throws IOException {
		response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
		List<SysUserEntityExcel> data = sysUserDao.exportRepairman(sysUserEntity);
		for (SysUserEntityExcel datum : data) {
			if (datum.getGender() == 1) {
				datum.setGenderString("男");
			} else {
				datum.setGenderString("女");
			}
			if ("0".equals(datum.getStatus())){
				datum.setStatus("禁用");
			}else {
				datum.setStatus("正常");
			}
			datum.setType(Constant.INT_TO_TYPE.get(datum.getTypeInt()));
		}
		response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
//		response.setContentType("application/vnd.ms-excel");
		response.setCharacterEncoding("utf-8");
		// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
		String fileName = URLEncoder.encode("用户信息统计表", "UTF-8").replaceAll("\\+", "%20");
		//response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
		response.setHeader("Content-disposition", "attachment;filename*=" + fileName + ".xlsx");
		EasyExcel.write(response.getOutputStream(), SysUserEntityExcel.class).sheet("数据").doWrite(data);
	}

	@Override
	public R nameList(String name) {
		return R.success("",sysUserDao.nameList(name));
	}

	@Override
	public R getOneById(Long id) {
		return R.success("",sysUserDao.getOneById(Integer.parseInt(id.toString())));
	}

	@Override
	public R resetPassword(Long userId) {

		return null;
	}


	/**
	 * 检查角色是否越权
	 */
	private void checkRole(SysUserEntity user){
		if(user.getRoleIdList() == null || user.getRoleIdList().size() == 0){
			return;
		}
		//如果不是超级管理员，则需要判断用户的角色是否自己创建
		if(user.getCreateUserId() == cn.edu.nsmc.common.utils.Constant.SUPER_ADMIN){
			return ;
		}

		//查询用户创建的角色列表
		List<Long> roleIdList = sysRoleService.queryRoleIdList(user.getCreateUserId());

		//判断是否越权
		if(!roleIdList.containsAll(user.getRoleIdList())){
			throw new RRException("新增用户所选角色，不是本人创建");
		}
	}
}
